LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

image_digit_conversion

2022/7/20

Python图片位数转换

一般购买嵌入式的屏幕,商家都会提供软件,可以将bmp文件转换成对应的C数组。

我们只需要提前转换好后放入代码中并烧录进单片机。

其实商家提供的软件只是做了简单的一件事,就是扫描并将图像位数进行转换。

我们常规使用的png图像是32位的,有4个通道,RGB三个通道以及一个α\alpha透明通道。

我们常规使用的jpeg以及bmp图像是24位的,只有RGB三个通道。

而我们使用的屏幕是16位的,所以需要进行位数的转换。


具体来说,24位bmp图像是RGB888

我们需要转换成16位的RGB565

举个例子 比如24位的像素RGB888是11010110 11010100 11101010(高位在前)

转换成16位的像素RGB565则只需要取R的高五位,G的高六位,B的高五位,如下图:

以python实现为例,假设输入的是一个24位的数,转换实现如下:

def rgb888_to_rgb565(rgb888):
    
    # 获得rgb各自对应的八位
    r = (rgb888 & 0xff0000) >> 16
    g = (rgb888 & 0x00ff00) >> 8
    b =  rgb888 & 0x0000ff

    # 888 -> 565
    r >>= 3
    g >>= 2
    b >>= 3

    return r << 11 | g << 5 | b

而python用opencv读取图像,是一个numpy数组,RGB通道各自的值是分离的。

假设我们模拟软件,将一个bmp图像转换成对应的16位c数组,python实现如下:

import numpy as np
import cv2 as cv


def img_rgb888_to_rgb565(img888):

    # 这里img是8位的 需要转类型到16位 不修改后续左移会溢出
    img888 = img888.astype(np.uint16)

    # opencv 是 BGR
    b = img888[:, :, 0]
    g = img888[:, :, 1]
    r = img888[:, :, 2]

    # 888 -> 565
    r >>= 3
    g >>= 2
    b >>= 3

    return r << 11 | g << 5 | b


def bit16_to_two_bit8(bit16):

    #高八位和低八位
    high_bit8 = (bit16 & 0xff00) >> 8
    low_bit8 = bit16 & 0x00ff

    return high_bit8, low_bit8


def write_list_to_c_file(data, save_path, array_type, array_name):

    with open(save_path, "w") as f:

        # 第一行 写类型和数组名
        f.write(array_type + " " + array_name + "[" + str(len(data)) + "]" + " = {")
        f.write('\n')

        # 循环写数据
        for i in range(len(data)):
            f.write(data[i])
            f.write(",")

            if i % 16 == 15:
                f.write("\n")

        # 尾行
        f.write("};")
        f.write("\n")


if __name__ == "__main__":
    img = cv.imread(r"./1.bmp")
    rgb565 = img_rgb888_to_rgb565(img)
    high, low = bit16_to_two_bit8(rgb565)
    bit16_array = np.concatenate((np.expand_dims(high, 2), np.expand_dims(low, 2)), axis=2)  # 高位在前
    data_list = list(map(lambda x: ("0X%02X" % x), bit16_array.flatten().tolist())) #flatten实现了横向扫描 要纵向扫描可以先转置
    write_list_to_c_file(data=data_list, save_path="./test.c", array_type="const unsigned char", array_name="gImage_1")

实现起来比较容易,但是有挺多需要注意的地方,我写在了注释


参考:https://bbs.csdn.net/topics/360140415

参考:https://blog.csdn.net/baidu_26678247/article/details/65629447